/*
 * @Author: BuddyCoder
 * @Date: 2021-12-17 16:36:38
 * @LastEditTime: 2022-01-05 12:14:26
 * @LastEditors: BuddyCoder
 * @Description: 
 * @FilePath: /pgbatis/src/unit.rs
 * MIT
 */
use std::{collections::HashMap, net::IpAddr};

use serde_json::{Value, json};
use tokio_postgres::{Row, types::Type};


const FMT_DATETIME: &str = "%Y-%m-%d %H:%M:%S";
const FMT_DATE: &str = "%Y-%m-%d";
const FMT_TIME: &str = "%H:%M:%S";

pub fn pg_value_to_json_value(pg_row: &Row) -> HashMap<String, Value> {
    let mut hash_map_row = HashMap::new();

    for column in pg_row.columns().iter() {
        let pg_type = column.type_().clone();
        let name = column.name();
        let key_name = name.to_string();
        match pg_type {
            Type::BOOL => {
                let value: Option<bool> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::CHAR => {
                let value: Option<i8> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::INT2 => {
                let value: Option<i16> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::INT4 => {
                let value: Option<i32> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::INT8 => {
                let value: Option<i64> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::OID => {
                let value: Option<u32> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }

            Type::FLOAT4 => {
                let value: Option<f32> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::FLOAT8 => {
                let value: Option<f64> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::VARCHAR | Type::TEXT => {
                let opt_value: Option<String> = pg_row.get(name);
                let value = match opt_value {
                    Some(value) => value,
                    None => "".to_string(),
                };
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::BYTEA => {
                let value: Option<Vec<u8>> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::INET => {
                let value: Option<IpAddr> = pg_row.get(name);
                let json_value = json!(value);
                hash_map_row.insert(key_name, json_value);
            }
            Type::TIMESTAMP => {
                let opt_value: Option<chrono::NaiveDateTime> = pg_row.get(name);
                let value_str = match opt_value {
                    Some(t) => t.format(FMT_DATETIME).to_string(),
                    None => "".to_string(),
                };
                let json_value = json!(value_str);
                hash_map_row.insert(key_name, json_value);
            }
            Type::TIMESTAMPTZ => {
                let opt_value: Option<chrono::NaiveDateTime> = pg_row.get(name);
                let value_str = match opt_value {
                    Some(t) => t.format(FMT_DATETIME).to_string(),
                    None => "".to_string(),
                };
                let json_value = json!(value_str);
                hash_map_row.insert(key_name, json_value);
            }
            Type::DATE => {
                let opt_value: Option<chrono::NaiveDate> = pg_row.get(name);
                let value_str = match opt_value {
                    Some(t) => t.format(FMT_DATE).to_string(),
                    None => "".to_string(),
                };
                let json_value = json!(value_str);
                hash_map_row.insert(key_name, json_value);
            }
            Type::TIME => {
                let opt_value: Option<chrono::NaiveTime> = pg_row.get(name);
                let value_str = match opt_value {
                    Some(t) => t.format(FMT_TIME).to_string(),
                    None => "".to_string(),
                };
                let json_value = json!(value_str);
                hash_map_row.insert(key_name, json_value);
            }
            _ => {}
        }
    }
    hash_map_row
}